﻿using System;
using System.Runtime.InteropServices;
using Aeon.Emulator.DebugSupport;

namespace Aeon.Emulator
{
    /// <summary>
    /// Contains the current state of the emulated x86 processor.
    /// </summary>
    [CLSCompliant(false)]
    public sealed class Processor : IRegisterContainer
    {
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the Processor class.
        /// </summary>
        internal Processor()
        {
            unsafe
            {
                gprBlock = (byte*)(Marshal.AllocCoTaskMem((sizeof(uint) * RegisterCount) + InstructionCacheSize));
                for(int i = 0; i < (sizeof(uint) * RegisterCount) + InstructionCacheSize; i++)
                    gprBlock[i] = 0;

                wordRegisterPointers = (void**)Marshal.AllocCoTaskMem(sizeof(void*) * 8).ToPointer();
                byteRegisterPointers = (byte**)Marshal.AllocCoTaskMem(sizeof(byte*) * 8).ToPointer();
                segmentRegisterPointers = (ushort**)Marshal.AllocCoTaskMem(sizeof(ushort*) * 8).ToPointer();
                defaultSegments16 = (uint**)Marshal.AllocCoTaskMem(sizeof(uint*) * 8).ToPointer();
                segmentBases = (uint*)Marshal.AllocCoTaskMem(sizeof(uint) * 8).ToPointer();
                defaultSibSegments32Mod0 = (uint**)Marshal.AllocCoTaskMem(sizeof(uint*) * 8).ToPointer();
                defaultSibSegments32Mod12 = (uint**)Marshal.AllocCoTaskMem(sizeof(uint*) * 8).ToPointer();
                for(int i = 0; i < 8; i++)
                    segmentBases[i] = 0;

                InitializeRegisterOffsets();
                PAX = wordRegisterPointers[0];
                PCX = wordRegisterPointers[1];
                PDX = wordRegisterPointers[2];
                PBX = wordRegisterPointers[3];

                PAH = byteRegisterPointers[4];
                PCH = byteRegisterPointers[5];
                PDH = byteRegisterPointers[6];
                PBH = byteRegisterPointers[7];

                PIP = gprBlock + 32;

                PSP = wordRegisterPointers[4];
                PBP = wordRegisterPointers[5];
                PSI = wordRegisterPointers[6];
                PDI = wordRegisterPointers[7];

                PES = segmentRegisterPointers[0];
                PCS = segmentRegisterPointers[1];
                PSS = segmentRegisterPointers[2];
                PDS = segmentRegisterPointers[3];
                PFS = segmentRegisterPointers[4];
                PGS = segmentRegisterPointers[5];

                baseOverrides = (uint**)Marshal.AllocCoTaskMem(sizeof(uint*) * 8).ToPointer();
                InitializeSegmentOverridePointers();
                InitializeDefaultSegmentPointers();
                debugRegisterBase = (uint*)(gprBlock + 60); // DR0
                this.CachedInstruction = gprBlock + (RegisterCount * sizeof(uint));
            }
        }
        ~Processor()
        {
            unsafe
            {
                Marshal.FreeCoTaskMem(new IntPtr(segmentBases));
                Marshal.FreeCoTaskMem(new IntPtr(baseOverrides));
                Marshal.FreeCoTaskMem(new IntPtr(wordRegisterPointers));
                Marshal.FreeCoTaskMem(new IntPtr(byteRegisterPointers));
                Marshal.FreeCoTaskMem(new IntPtr(segmentRegisterPointers));
                Marshal.FreeCoTaskMem(new IntPtr(defaultSegments16));
                Marshal.FreeCoTaskMem(new IntPtr(defaultSibSegments32Mod0));
                Marshal.FreeCoTaskMem(new IntPtr(defaultSibSegments32Mod12));
                Marshal.FreeCoTaskMem(new IntPtr(gprBlock));
            }
        }
        static Processor()
        {
            unsafe
            {
                parityLookup = (byte*)Marshal.AllocCoTaskMem(256);
            }

            for(int i = 0; i < 256; i++)
            {
                int bits = 0;
                for(int b = 0; b < 8; b++)
                {
                    if((i & (1 << b)) != 0)
                        bits++;
                }

                unsafe
                {
                    parityLookup[i] = (bits & 1) == 0 ? (byte)EFlags.Parity : (byte)0;
                }
            }
        }

        private unsafe void InitializeRegisterOffsets()
        {
            wordRegisterPointers[0] = gprBlock; // AX
            byteRegisterPointers[0] = gprBlock; // AL
            byteRegisterPointers[4] = gprBlock + 1; // AH

            wordRegisterPointers[1] = gprBlock + 4; // CX
            byteRegisterPointers[1] = gprBlock + 4; // CL
            byteRegisterPointers[5] = gprBlock + 5; // CH

            wordRegisterPointers[2] = gprBlock + 8; // DX
            byteRegisterPointers[2] = gprBlock + 8; // DL
            byteRegisterPointers[6] = gprBlock + 9; // DH

            wordRegisterPointers[3] = gprBlock + 12; // BX
            byteRegisterPointers[3] = gprBlock + 12; // BL
            byteRegisterPointers[7] = gprBlock + 13; // BH

            wordRegisterPointers[4] = gprBlock + 16; // SP
            wordRegisterPointers[5] = gprBlock + 20; // BP
            wordRegisterPointers[6] = gprBlock + 24; // SI
            wordRegisterPointers[7] = gprBlock + 28; // DI

            // IP = 32

            segmentRegisterPointers[0] = (ushort*)(gprBlock + 36); // ES
            segmentRegisterPointers[1] = (ushort*)(gprBlock + 40); // CS
            segmentRegisterPointers[2] = (ushort*)(gprBlock + 44); // SS
            segmentRegisterPointers[3] = (ushort*)(gprBlock + 48); // DS
            segmentRegisterPointers[4] = (ushort*)(gprBlock + 52); // FS
            segmentRegisterPointers[5] = (ushort*)(gprBlock + 56); // GS
        }
        private unsafe void InitializeSegmentOverridePointers()
        {
            baseOverrides[(int)SegmentRegister.Default] = null;
            baseOverrides[(int)SegmentRegister.ES] = &segmentBases[0];
            baseOverrides[(int)SegmentRegister.CS] = &segmentBases[1];
            baseOverrides[(int)SegmentRegister.SS] = &segmentBases[2];
            baseOverrides[(int)SegmentRegister.DS] = &segmentBases[3];
            baseOverrides[(int)SegmentRegister.FS] = &segmentBases[4];
            baseOverrides[(int)SegmentRegister.GS] = &segmentBases[5];
        }
        private unsafe void InitializeDefaultSegmentPointers()
        {
            defaultSegments16[0] = &segmentBases[3];
            defaultSegments16[1] = &segmentBases[3];
            defaultSegments16[2] = &segmentBases[2];
            defaultSegments16[3] = &segmentBases[2];
            defaultSegments16[4] = &segmentBases[3];
            defaultSegments16[5] = &segmentBases[3];
            defaultSegments16[6] = &segmentBases[2];
            defaultSegments16[7] = &segmentBases[3];

            defaultSibSegments32Mod0[0] = &segmentBases[3];
            defaultSibSegments32Mod0[1] = &segmentBases[3];
            defaultSibSegments32Mod0[2] = &segmentBases[3];
            defaultSibSegments32Mod0[3] = &segmentBases[3];
            defaultSibSegments32Mod0[4] = &segmentBases[2];
            defaultSibSegments32Mod0[5] = &segmentBases[3];
            defaultSibSegments32Mod0[6] = &segmentBases[3];
            defaultSibSegments32Mod0[7] = &segmentBases[3];

            defaultSibSegments32Mod12[0] = &segmentBases[3];
            defaultSibSegments32Mod12[1] = &segmentBases[3];
            defaultSibSegments32Mod12[2] = &segmentBases[3];
            defaultSibSegments32Mod12[3] = &segmentBases[3];
            defaultSibSegments32Mod12[4] = &segmentBases[2];
            defaultSibSegments32Mod12[5] = &segmentBases[2];
            defaultSibSegments32Mod12[6] = &segmentBases[3];
            defaultSibSegments32Mod12[7] = &segmentBases[3];
        }
        #endregion

        #region General Purpose
        /// <summary>
        /// Pointer to the EAX/AX/AL register.
        /// </summary>
        internal readonly unsafe void* PAX;
        /// <summary>
        /// Pointer to the EBX/BX/BL register.
        /// </summary>
        internal readonly unsafe void* PBX;
        /// <summary>
        /// Pointer to the ECX/CX/CL register.
        /// </summary>
        internal readonly unsafe void* PCX;
        /// <summary>
        /// Pointer to the EDX/DX/DL register.
        /// </summary>
        internal readonly unsafe void* PDX;
        /// <summary>
        /// Pointer to the AH register.
        /// </summary>
        internal readonly unsafe byte* PAH;
        /// <summary>
        /// Pointer to the BH register.
        /// </summary>
        internal readonly unsafe byte* PBH;
        /// <summary>
        /// Pointer to the CH register.
        /// </summary>
        internal readonly unsafe byte* PCH;
        /// <summary>
        /// Pointer to the DH register.
        /// </summary>
        internal readonly unsafe byte* PDH;

        /// <summary>
        /// Gets or sets the value of the EAX register.
        /// </summary>
        public int EAX
        {
            get { unsafe { return *(int*)PAX; } }
            set { unsafe { *(int*)PAX = value; } }
        }
        /// <summary>
        /// Gets the value of the EAX register.
        /// </summary>
        uint IRegisterContainer.EAX
        {
            get { return (uint)this.EAX; }
        }
        /// <summary>
        /// Gets or sets the value of the EBX register.
        /// </summary>
        public int EBX
        {
            get { unsafe { return *(int*)PBX; } }
            set { unsafe { *(int*)PBX = value; } }
        }
        /// <summary>
        /// Gets the value of the EAX register.
        /// </summary>
        uint IRegisterContainer.EBX
        {
            get { return (uint)this.EBX; }
        }
        /// <summary>
        /// Gets or sets the value of the ECX register.
        /// </summary>
        public int ECX
        {
            get { unsafe { return *(int*)PCX; } }
            set { unsafe { *(int*)PCX = value; } }
        }
        /// <summary>
        /// Gets the value of the EAX register.
        /// </summary>
        uint IRegisterContainer.ECX
        {
            get { return (uint)this.ECX; }
        }
        /// <summary>
        /// Gets or sets the value of the EDX register.
        /// </summary>
        public int EDX
        {
            get { unsafe { return *(int*)PDX; } }
            set { unsafe { *(int*)PDX = value; } }
        }
        /// <summary>
        /// Gets the value of the EAX register.
        /// </summary>
        uint IRegisterContainer.EDX
        {
            get { return (uint)this.EDX; }
        }
        /// <summary>
        /// Gets or sets the value of the AX register.
        /// </summary>
        public short AX
        {
            get { unsafe { return *(short*)PAX; } }
            set { unsafe { *(short*)PAX = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the BX register.
        /// </summary>
        public short BX
        {
            get { unsafe { return *(short*)PBX; } }
            set { unsafe { *(short*)PBX = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the CX register.
        /// </summary>
        public short CX
        {
            get { unsafe { return *(short*)PCX; } }
            set { unsafe { *(short*)PCX = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the DX register.
        /// </summary>
        public short DX
        {
            get { unsafe { return *(short*)PDX; } }
            set { unsafe { *(short*)PDX = value; } }
        }

        /// <summary>
        /// Gets or sets the value of the AL register.
        /// </summary>
        public byte AL
        {
            get { unsafe { return *(byte*)PAX; } }
            set { unsafe { *(byte*)PAX = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the AH register.
        /// </summary>
        public byte AH
        {
            get { unsafe { return *PAH; } }
            set { unsafe { *PAH = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the BL register.
        /// </summary>
        public byte BL
        {
            get { unsafe { return *(byte*)PBX; } }
            set { unsafe { *(byte*)PBX = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the BH register.
        /// </summary>
        public byte BH
        {
            get { unsafe { return *PBH; } }
            set { unsafe { *PBH = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the CL register.
        /// </summary>
        public byte CL
        {
            get { unsafe { return *(byte*)PCX; } }
            set { unsafe { *(byte*)PCX = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the CH register.
        /// </summary>
        public byte CH
        {
            get { unsafe { return *PCH; } }
            set { unsafe { *PCH = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the DL register.
        /// </summary>
        public byte DL
        {
            get { unsafe { return *(byte*)PDX; } }
            set { unsafe { *(byte*)PDX = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the DH register.
        /// </summary>
        public byte DH
        {
            get { unsafe { return *PDH; } }
            set { unsafe { *PDH = value; } }
        }
        #endregion

        #region Pointers
        /// <summary>
        /// Pointer to the EBP/BP register.
        /// </summary>
        internal unsafe readonly void* PBP;
        /// <summary>
        /// Pointer to the ESI/SI register.
        /// </summary>
        internal unsafe readonly void* PSI;
        /// <summary>
        /// Pointer to the EDI/DI register.
        /// </summary>
        internal unsafe readonly void* PDI;
        /// <summary>
        /// Pointer to the EIP/IP register.
        /// </summary>
        internal unsafe readonly void* PIP;
        /// <summary>
        /// Pointer to the ESP/SP register.
        /// </summary>
        internal unsafe readonly void* PSP;

        /// <summary>
        /// Gets or sets the value of the EBP register.
        /// </summary>
        public uint EBP
        {
            get { unsafe { return *(uint*)PBP; } }
            set { unsafe { *(uint*)PBP = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the ESI register.
        /// </summary>
        public uint ESI
        {
            get { unsafe { return *(uint*)PSI; } }
            set { unsafe { *(uint*)PSI = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the EDI register.
        /// </summary>
        public uint EDI
        {
            get { unsafe { return *(uint*)PDI; } }
            set { unsafe { *(uint*)PDI = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the EIP register.
        /// </summary>
        public uint EIP
        {
            get { unsafe { return *(uint*)PIP; } }
            set { unsafe { *(uint*)PIP = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the ESP register.
        /// </summary>
        public uint ESP
        {
            get { unsafe { return *(uint*)PSP; } }
            set { unsafe { *(uint*)PSP = value; } }
        }

        /// <summary>
        /// Gets or sets the value of the BP register.
        /// </summary>
        public ushort BP
        {
            get { unsafe { return *(ushort*)PBP; } }
            set { unsafe { *(ushort*)PBP = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the SI register.
        /// </summary>
        public ushort SI
        {
            get { unsafe { return *(ushort*)PSI; } }
            set { unsafe { *(ushort*)PSI = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the DI register.
        /// </summary>
        public ushort DI
        {
            get { unsafe { return *(ushort*)PDI; } }
            set { unsafe { *(ushort*)PDI = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the IP register.
        /// </summary>
        public ushort IP
        {
            get { unsafe { return *(ushort*)PIP; } }
            set { unsafe { *(ushort*)PIP = value; } }
        }
        /// <summary>
        /// Gets or sets the value of the SP register.
        /// </summary>
        public ushort SP
        {
            get { unsafe { return *(ushort*)PSP; } }
            set { unsafe { *(ushort*)PSP = value; } }
        }
        #endregion

        #region Segment Registers
        /// <summary>
        /// Pointer to the ES register.
        /// </summary>
        internal unsafe readonly ushort* PES;
        /// <summary>
        /// Pointer to the CS register.
        /// </summary>
        internal unsafe readonly ushort* PCS;
        /// <summary>
        /// Pointer to the SS register.
        /// </summary>
        internal unsafe readonly ushort* PSS;
        /// <summary>
        /// Pointer to the DS register.
        /// </summary>
        internal unsafe readonly ushort* PDS;
        /// <summary>
        /// Pointer to the FS register.
        /// </summary>
        internal unsafe readonly ushort* PFS;
        /// <summary>
        /// Pointer to the GS register.
        /// </summary>
        internal unsafe readonly ushort* PGS;

        /// <summary>
        /// Gets or sets the value of the ES register.
        /// </summary>
        public ushort ES
        {
            get { unsafe { return *PES; } }
        }
        /// <summary>
        /// Gets or sets the value of the CS register.
        /// </summary>
        public ushort CS
        {
            get { unsafe { return *PCS; } }
        }
        /// <summary>
        /// Gets or sets the value of the SS register.
        /// </summary>
        public ushort SS
        {
            get { unsafe { return *PSS; } }
        }
        /// <summary>
        /// Gets or sets the value of the DS register.
        /// </summary>
        public ushort DS
        {
            get { unsafe { return *PDS; } }
        }
        /// <summary>
        /// Gets or sets the value of the FS register.
        /// </summary>
        public ushort FS
        {
            get { unsafe { return *PFS; } }
        }
        /// <summary>
        /// Gets or sets the value of the GS register.
        /// </summary>
        public ushort GS
        {
            get { unsafe { return *PGS; } }
        }

        /// <summary>
        /// Gets the current base address associated with the ES register.
        /// </summary>
        public uint ESBase
        {
            get { unsafe { return segmentBases[0]; } }
        }
        /// <summary>
        /// Gets the current base address associated with the CS register.
        /// </summary>
        public uint CSBase
        {
            get { unsafe { return segmentBases[1]; } }
        }
        /// <summary>
        /// Gets the current base address associated with the SS register.
        /// </summary>
        public uint SSBase
        {
            get { unsafe { return segmentBases[2]; } }
        }
        /// <summary>
        /// Gets the current base address associated with the DS register.
        /// </summary>
        public uint DSBase
        {
            get { unsafe { return segmentBases[3]; } }
        }
        /// <summary>
        /// Gets the current base address associated with the FS register.
        /// </summary>
        public uint FSBase
        {
            get { unsafe { return segmentBases[4]; } }
        }
        /// <summary>
        /// Gets the current base address associated with the GS register.
        /// </summary>
        public uint GSBase
        {
            get { unsafe { return segmentBases[5]; } }
        }
        #endregion

        #region Other
        /// <summary>
        /// The value of the EFLAGS register.
        /// </summary>
        public EFlags Flags = EFlags.InterruptEnable | EFlags.Identification | EFlags.Reserved1;
        /// <summary>
        /// Gets the value of the EFLAGS register.
        /// </summary>
        EFlags IRegisterContainer.Flags
        {
            get { return this.Flags; }
        }
        /// <summary>
        /// The current segment override prefix.
        /// </summary>
        public SegmentRegister SegmentOverride;
        /// <summary>
        /// The current instruction repeat prefix.
        /// </summary>
        public RepeatPrefix RepeatPrefix;
        /// <summary>
        /// The value of the CR0 register.
        /// </summary>
        public CR0 CR0;
        /// <summary>
        /// Gets the value of the CR0 register.
        /// </summary>
        CR0 IRegisterContainer.CR0
        {
            get { return this.CR0; }
        }
        /// <summary>
        /// The value of the CR2 register.
        /// </summary>
        public uint CR2;
        /// <summary>
        /// The value of the CR3 register.
        /// </summary>
        public uint CR3;
        /// <summary>
        /// Gets or sets the value of the carry flag.
        /// </summary>
        public bool CarryFlag
        {
            get
            {
                return (Flags & EFlags.Carry) != 0;
            }
            set
            {
                if(value)
                    Flags |= EFlags.Carry;
                else
                    Flags &= ~EFlags.Carry;
            }
        }
        /// <summary>
        /// Gets or sets the value of the overflow flag.
        /// </summary>
        public bool OverflowFlag
        {
            get
            {
                return (Flags & EFlags.Overflow) != 0;
            }
            set
            {
                if(value)
                    Flags |= EFlags.Overflow;
                else
                    Flags &= ~EFlags.Overflow;
            }
        }
        /// <summary>
        /// Gets or sets the value of the zero flag.
        /// </summary>
        public bool ZeroFlag
        {
            get
            {
                return (Flags & EFlags.Zero) != 0;
            }
            set
            {
                if(value)
                    Flags |= EFlags.Zero;
                else
                    Flags &= ~EFlags.Zero;
            }
        }
        /// <summary>
        /// Gets or sets the value of the sign flag.
        /// </summary>
        public bool SignFlag
        {
            get
            {
                return (Flags & EFlags.Sign) != 0;
            }
            set
            {
                if(value)
                    Flags |= EFlags.Sign;
                else
                    Flags &= ~EFlags.Sign;
            }
        }
        /// <summary>
        /// Gets or sets the value of the parity flag.
        /// </summary>
        public bool ParityFlag
        {
            get
            {
                return (Flags & EFlags.Parity) != 0;
            }
            set
            {
                if(value)
                    Flags |= EFlags.Parity;
                else
                    Flags &= ~EFlags.Parity;
            }
        }
        /// <summary>
        /// Gets or sets the value of the direction flag.
        /// </summary>
        public bool DirectionFlag
        {
            get
            {
                return (Flags & EFlags.Direction) != 0;
            }
            set
            {
                if(value)
                    Flags |= EFlags.Direction;
                else
                    Flags &= ~EFlags.Direction;
            }
        }
        /// <summary>
        /// Gets the width of the current operands in bits.
        /// </summary>
        public int OperandSize
        {
            get
            {
                uint bit = (GlobalSize ^ SizeOverride) & 1u;
                return bit == 0 ? 16 : 32;
            }
        }
        /// <summary>
        /// Gets the width of the current addressing mode in bits.
        /// </summary>
        public int AddressSize
        {
            get
            {
                uint bit = (GlobalSize ^ SizeOverride) & 2u;
                return bit == 0 ? 16 : 32;
            }
        }
        #endregion

        #region FPU
        /// <summary>
        /// The floating-point unit.
        /// </summary>
        public readonly FPU FPU = new FPU();
        #endregion

        #region Internal Properties
        /// <summary>
        /// Gets the current index to use for decoders and emulators.
        /// </summary>
        internal uint SizeModeIndex
        {
            get
            {
                return SizeOverride ^ GlobalSize;
            }
        }
        /// <summary>
        /// Gets a value indicating whether an instruction prefix is in effect.
        /// </summary>
        internal bool InPrefix
        {
            get
            {
                return this.PrefixCount > 0;
            }
        }
        #endregion

        #region Internal Methods
        /// <summary>
        /// Updates the flags register for a byte result.
        /// </summary>
        /// <param name="sValue">Signed result value.</param>
        /// <param name="uValue">Unsigned result value.</param>
        /// <param name="mask">Mask of flags to update.</param>
        internal void ByteUpdateFlags(int sValue, uint uValue, EFlags mask)
        {
            EFlags flags = (EFlags)uValue & EFlags.Sign;

            flags |= (EFlags)(uValue >> 8) & EFlags.Carry;

            if((uValue & 0xFF) == 0)
                flags |= EFlags.Zero;

            if(sValue < sbyte.MinValue || sValue > sbyte.MaxValue)
                flags |= EFlags.Overflow;

            unsafe
            {
                flags |= (EFlags)parityLookup[uValue & 0xFF];
            }

            flags &= mask;
            this.Flags = (this.Flags & ~mask) | flags;
        }
        /// <summary>
        /// Updates the flags register for a word result.
        /// </summary>
        /// <param name="sValue">Signed result value.</param>
        /// <param name="uValue">Unsigned result value.</param>
        /// <param name="mask">Mask of flags to update.</param>
        internal void WordUpdateFlags(int sValue, uint uValue, EFlags mask)
        {
            EFlags flags = (EFlags)(uValue >> 8) & EFlags.Sign;

            flags |= (EFlags)(uValue >> 16) & EFlags.Carry;

            if((uValue & 0xFFFF) == 0)
                flags |= EFlags.Zero;

            if(sValue < short.MinValue || sValue > short.MaxValue)
                flags |= EFlags.Overflow;

            unsafe
            {
                flags |= (EFlags)parityLookup[uValue & 0xFF];
            }

            flags &= mask;
            this.Flags = (this.Flags & ~mask) | flags;
        }
        /// <summary>
        /// Updates the flags register for a dword result.
        /// </summary>
        /// <param name="sValue">Signed result value.</param>
        /// <param name="uValue">Unsigned result value.</param>
        /// <param name="mask">Mask of flags to update.</param>
        internal void DWordUpdateFlags(long sValue, ulong uValue, EFlags mask)
        {
            EFlags flags = (EFlags)(uValue >> 24) & EFlags.Sign;

            flags |= (EFlags)(uValue >> 32) & EFlags.Carry;

            if((uValue & 0xFFFFFFFF) == 0)
                flags |= EFlags.Zero;

            if(sValue < int.MinValue || sValue > int.MaxValue)
                flags |= EFlags.Overflow;

            unsafe
            {
                flags |= (EFlags)parityLookup[uValue & 0xFF];
            }

            flags &= mask;
            this.Flags = (this.Flags & ~mask) | flags;
        }
        internal uint GetOverrideBase(SegmentIndex defaultSegment)
        {
            unsafe
            {
                uint* address = baseOverrides[(int)this.SegmentOverride];
                if(address != null)
                    return *address;
                else
                    return segmentBases[(int)defaultSegment];
            }
        }

        internal byte[] GetCurrentState()
        {
            unsafe
            {
                byte[] buffer = new byte[sizeof(uint) * (RegisterCount + 9)];
                Marshal.Copy(new IntPtr(gprBlock), buffer, 0, sizeof(uint) * RegisterCount);
                Marshal.Copy(new IntPtr(segmentBases), buffer, sizeof(uint) * RegisterCount, 8 * sizeof(uint));

                int flagsIndex = sizeof(uint) * (RegisterCount + 8);
                buffer[flagsIndex] = (byte)((uint)this.Flags & 0xFF);
                buffer[flagsIndex + 1] = (byte)(((uint)this.Flags >> 8) & 0xFF);
                buffer[flagsIndex + 2] = (byte)(((uint)this.Flags >> 16) & 0xFF);
                buffer[flagsIndex + 3] = (byte)(((uint)this.Flags >> 24) & 0xFF);

                return buffer;
            }
        }
        internal void SetCurrentState(byte[] state)
        {
            unsafe
            {
                Marshal.Copy(state, 0, new IntPtr(gprBlock), sizeof(uint) * RegisterCount);
                Marshal.Copy(state, sizeof(uint) * RegisterCount, new IntPtr(segmentBases), sizeof(uint) * 8);

                int flagsIndex = sizeof(uint) * (RegisterCount + 8);
                this.Flags = (EFlags)(state[flagsIndex] | (state[flagsIndex + 1] << 8) | (state[flagsIndex + 2] << 16) | (state[flagsIndex + 3] << 24));
            }
        }

        internal unsafe byte* GetRegisterBytePointer(int rmCode)
        {
            return byteRegisterPointers[rmCode];
        }
        internal unsafe void* GetRegisterWordPointer(int rmCode)
        {
            return wordRegisterPointers[rmCode];
        }
        internal unsafe ushort* GetSegmentRegisterPointer(int code)
        {
            return segmentRegisterPointers[code];
        }
        internal unsafe uint* GetDebugRegisterPointer(int code)
        {
            return &debugRegisterBase[code];
        }

        /// <summary>
        /// Clears prefix information after an instruction.
        /// </summary>
        /// <remarks>
        /// This method must be called explicitly by instructions with no operands.
        /// </remarks>
        internal void InstructionEpilog()
        {
            this.SegmentOverride = SegmentRegister.Default;
            this.RepeatPrefix = RepeatPrefix.None;
            this.SizeOverride = 0;
            this.PrefixCount = 0;
            this.TemporaryInterruptMask = false;
        }
        #endregion

        #region Internal Fields
        /// <summary>
        /// Contains operand size (bit 0) and address size (bit 1) overrides set
        /// by instruction prefixes.
        /// </summary>
        internal uint SizeOverride;
        /// <summary>
        /// Contains operand size (bit 0) and address size (bit 1) for the
        /// processor's default state.
        /// </summary>
        internal uint GlobalSize;
        /// <summary>
        /// The number of instruction prefixes currently in effect.
        /// </summary>
        internal int PrefixCount;
        /// <summary>
        /// Array of pointers to segment registers.
        /// </summary>
        internal unsafe readonly ushort** segmentRegisterPointers;
        /// <summary>
        /// Array of pointers to segment override bases.
        /// </summary>
        internal unsafe readonly uint** baseOverrides;
        /// <summary>
        /// Array of pointers to default 16-bit segment bases.
        /// </summary>
        internal unsafe readonly uint** defaultSegments16;
        /// <summary>
        /// Array of pointers to default 32-bit SIB segment bases for MOD=1 or 2.
        /// </summary>
        internal unsafe readonly uint** defaultSibSegments32Mod12;
        /// <summary>
        /// Array of pointers to default 32-bit SIB segment bases for MOD=0.
        /// </summary>
        internal unsafe readonly uint** defaultSibSegments32Mod0;
        /// <summary>
        /// Array of segment base values.
        /// </summary>
        internal unsafe readonly uint* segmentBases;
        /// <summary>
        /// 16-byte cache of the current instruction.
        /// </summary>
        internal unsafe readonly byte* CachedInstruction;
        /// <summary>
        /// Pointer to the next byte in the cached instruction buffer.
        /// </summary>
        internal unsafe byte* CachedIP;
        /// <summary>
        /// Instruction pointer for the first byte of the current instruction.
        /// </summary>
        internal uint StartEIP;
        /// <summary>
        /// Specifies whether interrupts are disabled for the next instruction.
        /// </summary>
        internal bool TemporaryInterruptMask;
        #endregion

        #region Private Fields
        /// <summary>
        /// Pointer to first general-purpose register.  Each register is 4 bytes apart.
        /// </summary>
        private unsafe readonly byte* gprBlock;
        private unsafe readonly void** wordRegisterPointers;
        private unsafe readonly byte** byteRegisterPointers;
        private unsafe readonly uint* debugRegisterBase;
        #endregion

        #region Private Static Fields
        internal static unsafe readonly byte* parityLookup;
        #endregion

        #region Private Constants
        /// <summary>
        /// The number of registers contained in the GPR block.
        /// </summary>
        private const int RegisterCount = 24;
        /// <summary>
        /// The number of bytes used to cache the current instruction.
        /// </summary>
        private const int InstructionCacheSize = 16;
        #endregion
    }
}
